/**
 * 
 */
package strain.demo;

import java.util.ArrayList;
import java.util.List;

import strain.domain.InconsistentDomainException;

public class AllDifferent<T> implements Constraint<T>{
    
    List<DiscreteVariable<T>> variables;
    
    public AllDifferent(final List<DiscreteVariable<T>> variables){
        this.variables = variables;
    }
    
    public AllDifferent<T> solverCopy(final Solver<T> solver){
        List<DiscreteVariable<T>> solverVariables = new ArrayList<DiscreteVariable<T>>(this.variables.size());
        for(DiscreteVariable<T> variable: this.variables){
            DiscreteVariable<T> solverVariable = solver.getVariable(variable.getName());
            solverVariables.add(solverVariable);
        }
        return new AllDifferent<T>(solverVariables);
    }
    
    public boolean apply() throws InconsistentDomainException{
        // if a variable is bound, it's value can be removed from the domains of the other variables
        // ... more generally (for n > 1) ...
        // if there is a group of n variables such that the size of the union of their domains is n,
        // then that union can be removed from the domains of non-group members.
        boolean result = false;
        for(DiscreteVariable<T> boundVariable: this.variables){
            if (boundVariable.isBound()){
                T boundValue = boundVariable.getBoundValue();
                for(DiscreteVariable<T> variable: this.variables){
                    if (!boundVariable.equals(variable)){
                        result = result || variable.remove(boundValue);
                    }
                }
            }
        }
        return result;
    }
    
    @Override
    public String toString(){
        List<String> variableNames = new ArrayList<String>(this.variables.size());
        for(DiscreteVariable<T> variable: this.variables){
            variableNames.add(variable.getName());
        }
        return  "[AllDifferent:" + variableNames.toString() + "]";
    }
    
}